package com.zxg.jdbc;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Callable;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.ArrayUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.jdbc.annotation.ColumIngore;
import com.jdbc.annotation.PartitionID;
import com.jdbc.annotation.TableColum;
import com.jdbc.annotation.TableID;
import com.jdbc.annotation.TableName;
import com.jdbc.annotation.TableUnique;
import com.jdbc.util.InvokerUtil;
import com.taobao.common.dao.persistence.DBRoute;
import com.taobao.common.dao.persistence.exception.DAOException;

public class JDBCBaseDao {
  /**
   * 日志
   */
  protected final static Logger    log                = LoggerFactory.getLogger("dao");

  JDBCBaseDaoSupport               jdbcBaseDaoSupport = null;

  /**
   * 按字母排序 A-Z_a-z
   */
  private static Comparator<Field> sortFieldByName    = new Comparator<Field>() {
                                                        @Override
                                                        public int compare(Field o1, Field o2) {
                                                          return o1.getName().compareTo(o2.getName());
                                                        }
                                                      };

  /**
   * 打印SQL
   * 
   * @param dataSrc
   *          数据源
   * @param query
   *          SQL语句
   * @param params
   *          参数
   */
  private static void showSQL(DBRoute dbRoute, String query, Object... params) {
    StringBuilder sb = new StringBuilder();
    sb.append("执行SQL:").append(query).append("数据源:").append(dbRoute.getXid()).append("参数：");

    for (int i = 0; i < params.length; i++) {
      if ((params[i] != null) && (params[i].toString().length() > 300)) {
        continue;
      }

      sb.append(("【")).append(i).append(" = ").append(params[i]).append("】");
    }

    log.info(sb.toString());
  }

  /**
   * 删除对象<code>（该对象必须是含有@Id字段）</code>
   * 
   * @param dataSrc
   *          数据源
   * @param obj
   *          对象
   * @return 删除结果 直接返回数据库所影响的记录数
   */
  public long delete(DBRoute dbRoute, Object obj) throws DAOException {
    String table = getTableName(obj.getClass());
    Class objClazz = obj.getClass();
    List<Object> params = new ArrayList<Object>();

    Set<Field> fields = getFields(objClazz);
    StringBuilder sql = new StringBuilder();
    sql.append("DELETE FROM ").append(table).append(" WHERE ");

    for (Field field : fields) {
      if (field.getAnnotation(TableID.class) != null) {
        sql.append(getColumnName(field)).append(" = ?  AND ");
        params.add(InvokerUtil.invokeGet(obj, field));
      }
    }

    sql.delete(sql.length() - 4, sql.length());

    showSQL(dbRoute, sql.toString(), params.toArray());

    return update(false, dbRoute, sql.toString(), params.toArray());
  }

  public long update(boolean debug, DBRoute dbRoute, String query, Object... args) throws DAOException {
    Connection conn = null;
    PreparedStatement ps = null;
    ResultSet rset = null;

    try {
      conn = jdbcBaseDaoSupport.getConnection(dbRoute);
      ps = conn.prepareStatement(query);

      setArgs(ps, args);

      int res = ps.executeUpdate();

      if (res <= 0) {
        return 0L;
      } else {
        return (long) res;
      }
    } catch (SQLException e) {
      log.error(query + e.getMessage(), e);
      throw new DAOException(e);
    } finally {
      closeAll(rset, ps, conn, dbRoute);
    }
  }

  private void setArgs(PreparedStatement ps, Object... args) throws SQLException {
    if (ArrayUtils.isEmpty(args)) {
      return;
    }

    for (int i = 0; i < args.length; i++) {
      Object obj = args[i];

      if (obj == null) {
        ps.setString(i + 1, null);
      } else if (obj instanceof Integer) {
        ps.setInt(i + 1, ((Integer) obj).intValue());
      } else if (obj instanceof Long) {
        ps.setLong(i + 1, ((Long) obj).longValue());
      } else if (obj instanceof Float) {
        ps.setFloat(i + 1, ((Float) obj).floatValue());
      } else if (obj instanceof String) {
        ps.setString(i + 1, obj.toString());
      } else if (obj instanceof Boolean) {
        ps.setBoolean(i + 1, ((Boolean) obj).booleanValue());
      } else if (obj instanceof Double) {
        ps.setDouble(i + 1, ((Double) obj).doubleValue());
      } else if (obj instanceof Date) {
        ps.setTimestamp(i + 1, new java.sql.Timestamp(((Date) obj).getTime()));
      }
    }
  }

  public final void closeAll(ResultSet rs, PreparedStatement ps, Connection conn, DBRoute dbroute) throws DAOException {
    closeQuitely(rs);
    closeQuitely(ps);
    jdbcBaseDaoSupport.closeConnection(conn, dbroute);
  }

  public final void closeQuitely(ResultSet rs) throws DAOException {
    try {
      if (rs != null) {
        rs.close();
      }
    } catch (Exception e) {
      log.error(e.getMessage(), e);
      throw new DAOException(e);
    }
  }

  public static final void closeQuitely(PreparedStatement ps) throws DAOException {
    try {
      if (ps != null) {
        ps.close();
      }
    } catch (Exception e) {
      log.error(e.getMessage(), e);
      throw new DAOException(e);
    }
  }

  /**
   * 主键判断
   * 
   * @param field
   *          字段
   * @return true:主键 false:不是主键
   */
  private static boolean isId(Field field) {
    return field.getAnnotation(TableID.class) != null;
  }

  /**
   * 批量删除
   * 
   * @param dataSrc
   *          数据源
   * @param c
   *          对象集合
   * @return 数据库影响的记录数
   */
  public long deleteBatch(DBRoute dbRoute, Collection<? extends Object> c) throws DAOException {
    if (CollectionUtils.isEmpty(c)) {
      return 0;
    }

    Class objClazz = c.iterator().next().getClass();
    String table = getTableName(objClazz);
    StringBuilder sql = new StringBuilder();
    sql.append("DELETE FROM ").append(table).append(" where ");

    List<Object> params = new ArrayList<Object>();

    for (Object obj : c) {
      sql.append("(");

      for (Field field : getFields(objClazz)) {
        if (isId(field)) {
          Object value = InvokerUtil.invokeGet(obj, field);
          sql.append(field.getName()).append(" =");
          sql.append(" ? and ");
          params.add(value);
        }
      }

      sql.delete(sql.length() - 4, sql.length());
      sql.append(") or ");
    }

    sql.delete(sql.length() - 4, sql.length());

    showSQL(dbRoute, sql.toString(), params.toArray());

    return update(false, dbRoute, sql.toString(), params.toArray());
  }

  /**
   * 根据主键查找对象
   * 
   * @param dataSrc
   *          数据源
   * @param objClazz
   *          对象类型
   * @param params
   *          参数
   * @return 对象
   */
  public <T> T findById(DBRoute dbRoute, final Class<T> objClazz, Object... params) throws DAOException {
    StringBuilder fieldStr = new StringBuilder();

    for (Field field : getFields(objClazz)) {
      if (field.getAnnotation(TableID.class) != null) {
        fieldStr.append(field.getName()).append(",");
      }
    }

    fieldStr.delete(fieldStr.length() - 1, fieldStr.length());

    return findByFields(dbRoute, objClazz, fieldStr.toString(), params);
  }

  /**
   * 根据字段查找对象
   * 
   * @param dataSrc
   *          数据源
   * @param objClazz
   *          对象类型
   * @param fields
   *          字段名,逗号隔开
   * @param params
   *          参数
   * @return 对象
   */
  public <T> T findByFields(DBRoute dbRoute, final Class<T> objClazz, String fields, Object... params) throws DAOException {
    String table = null;

    if (objClazz == null) {
      throw new DAOException("entity could not be null ");
    }

    table = getTableName(objClazz);

    StringBuilder sql = new StringBuilder();
    sql.append("select * from ").append(table).append(" where ");

    String[] idArray = fields.split(",");

    for (String id : idArray) {
      for (Field field : getFields(objClazz)) {
        if (field.getName().equals(id)) {
          sql.append(getColumnName(field)).append(" = ? and ");
        }
      }
    }

    sql.delete(sql.length() - 4, sql.length());

    return getSingleResult(dbRoute, objClazz, sql.toString(), params);
  }

  /**
   * 获得数据库表中的列名
   * 
   * @param field
   *          字段
   * @return 数据库表中的列名
   */
  public String getColumnName(Field field) {
    return getColumnName(field, true);
  }

  public String getColumnName(Field field, boolean add) {
    TableColum col = field.getAnnotation(TableColum.class);

    if ((col != null) && col.name() != null && !col.name().equals("")) {
      if (add) {
        return "`" + col.name() + "`";
      } else {
        return col.name();
      }
    }
    if (add) {
      return "`" + field.getName() + "`";
    } else {
      return field.getName();
    }

  }

  /**
   * 获得全部字段包括继承的，取得的字段按照字母排序A-Z-a-z
   * 
   * @param clazz
   *          对象类型
   * @return 所有字段不包括被static或<code>@Transient</code>或Transient修饰的字段
   */
  private Set<Field> getFields(Class clazz) {
    Set<Field> fieldSet = new HashSet<Field>();
    Field[] fs = clazz.getDeclaredFields();
    fieldSet = new HashSet<Field>(Arrays.asList(fs));

    for (Iterator<Field> i = fieldSet.iterator(); i.hasNext();) {
      if (skipField(i.next())) {
        i.remove();
      }
    }

    List<Field> fieldList = new ArrayList<Field>();
    fieldList.addAll(fieldSet);

    Collections.sort(fieldList, sortFieldByName);
    fieldSet.clear();
    fieldSet.addAll(fieldList);

    return fieldSet;
  }

  public abstract class JDBCExecutor<T> implements Callable<T> {
    String            query;
    Object[]          params;
    boolean           debug = false;
    protected DBRoute src   = null;

    public JDBCExecutor(String query, Object... params) {
      this.query = query;
      this.params = params;
    }

    public JDBCExecutor(DBRoute src, String query, Object... params) {
      this.query = query;
      this.params = params;
      this.src = src;
    }

    public JDBCExecutor(boolean debug, String query, Object... params) {
      this.debug = debug;
      this.query = query;
      this.params = params;
    }

    public T call() throws DAOException {
      Connection conn = null;
      PreparedStatement ps = null;
      ResultSet rs = null;
      T t = null;

      try {
        conn = jdbcBaseDaoSupport.getConnection(src);
        ps = conn.prepareStatement(query);
        if (debug) {
          log.info("[Build Query :]" + query.toString());
        }
        setArgs(ps, params);
        rs = ps.executeQuery();
        t = doWithResultSet(rs);
      } catch (SQLException e) {
        log.error(query + e.getMessage(), e);
        throw new DAOException(e);
      } finally {
        closeAll(rs, ps, conn, src);
      }

      return t;
    }

    public abstract T doWithResultSet(ResultSet rs) throws SQLException, DAOException;
  }

  /**
   * 获得集合
   * 
   * @param dataSrc数据源
   * @param objClazz对象类型
   * @param query查询语句
   * @param params参数
   * @return 对象集合
   */
  public <T> List<T> getResultList(DBRoute dbRoute, final Class<T> objClazz, String query, Object... params) throws DAOException {

    showSQL(dbRoute, query.toString(), params);

    if ((objClazz == Long.class) || (objClazz == String.class) || (objClazz == Integer.class) || (objClazz == Double.class) || (objClazz == Float.class)
        || (objClazz == Boolean.class)) {
      return new JDBCExecutor<List<T>>(dbRoute, query, params) {
        @Override
        public List<T> doWithResultSet(ResultSet rs) throws SQLException, DAOException {
          List<T> list = new ArrayList<T>();

          while (rs.next()) {
            Object obj = null;
            Object objGet = rs.getObject(1);

            if (objGet != null) {
              try {
                if (Long.class.equals(objClazz)) {
                  obj = new Long(objGet.toString());
                } else if (String.class.equals(objClazz)) {
                  obj = new String(objGet.toString());
                } else if (Integer.class.equals(objClazz)) {
                  obj = new Integer(objGet.toString());
                } else if (Double.class.equals(objClazz)) {
                  obj = new Double(objGet.toString());
                } else if (Float.class.equals(objClazz)) {
                  obj = new Float(objGet.toString());
                } else if (Boolean.class.equals(objClazz)) {
                  String booleanString = objGet.toString();

                  if (booleanString.equals("1") || booleanString.equalsIgnoreCase("true")) {
                    obj = new Boolean(true);
                  } else {
                    obj = new Boolean(false);
                  }
                }
              } catch (Exception e) {
                log.error(e.getMessage(), e);
                throw new DAOException(e);
              }

              list.add((T) obj);
            }
          }

          return list;
        }
      }.call();
    }

    return new JDBCExecutor<List<T>>(dbRoute, query, params) {
      @Override
      public List<T> doWithResultSet(ResultSet rs) throws SQLException, DAOException {
        List<T> list = new ArrayList<T>();
        Set<Field> fs = getFields(objClazz);

        while (rs.next()) {
          Object obj = null;

          try {
            obj = objClazz.newInstance();

            for (Field field : fs) {
              try {
                Object columnValue = rs.getObject(getColumnName(field, false));

                if (columnValue != null) {
                  setValue(obj, objClazz, field, columnValue);
                }
              } catch (SQLException e) {
                continue;
              }
            }
          } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new DAOException(e);
          }
          list.add((T) obj);
        }

        return list;
      }
    }.call();
  }

  /**
   * 获得单个对象
   * 
   * @param dataSrc
   *          数据源
   * @param objClazz
   *          对象类型
   * @param query
   *          查询语句
   * @param params
   *          参数
   * @return 对象
   */
  public <T> T getSingleResult(DBRoute dbRoute, final Class<T> objClazz, final String query, Object... params) throws DAOException {
    showSQL(dbRoute, query.toString(), params);

    if ((objClazz == Long.class) || (objClazz == String.class) || (objClazz == Integer.class) || (objClazz == Double.class) || (objClazz == Float.class)
        || (objClazz == Boolean.class)) {
      return new JDBCExecutor<T>(dbRoute, query, params) {
        @Override
        public T doWithResultSet(ResultSet rs) throws SQLException, DAOException {
          Object obj = null;

          if (!rs.next()) {
            if ((objClazz == Integer.class) && ((query.toUpperCase().indexOf("COUNT") > -1) || (query.toUpperCase().indexOf("SUM") > -1))) {

              return (T) new Integer("0");
            } else if ((objClazz == Long.class) && ((query.toUpperCase().indexOf("COUNT") > -1) || (query.toUpperCase().indexOf("SUM") > -1))) {

              return (T) new Long("0");
            } else {

              return null;
            }
          }
          if (rs.getObject(1) == null) {

            return null;
          }
          try {
            if (Long.class.equals(objClazz)) {
              obj = new Long(rs.getObject(1).toString());
            } else if (String.class.equals(objClazz)) {
              obj = new String(rs.getObject(1).toString());
            } else if (Integer.class.equals(objClazz)) {
              obj = new Integer(rs.getObject(1).toString());
            } else if (Double.class.equals(objClazz)) {
              obj = new Double(rs.getObject(1).toString());
            } else if (Float.class.equals(objClazz)) {
              obj = new Float(rs.getObject(1).toString());
            } else if (Boolean.class.equals(objClazz)) {
              String booleanString = rs.getObject(1).toString();

              if (booleanString.equals("1") || booleanString.equalsIgnoreCase("true")) {
                obj = new Boolean(true);
              } else {
                obj = new Boolean(false);
              }
            }
          } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new DAOException(e);
          }

          return (T) obj;
        }
      }.call();
    }

    return new JDBCExecutor<T>(dbRoute, query, params) {
      @Override
      public T doWithResultSet(ResultSet rs) throws SQLException, DAOException {
        Set<Field> fs = getFields(objClazz);

        if (!rs.next()) {

          return null;
        }

        Object obj = null;

        try {
          obj = objClazz.newInstance();

          for (Field field : fs) {
            try {
              Object columnValue = rs.getObject(getColumnName(field, false));

              if (columnValue != null) {
                setValue(obj, objClazz, field, columnValue);
              }
            } catch (SQLException e) {
              continue;
            }
          }
        } catch (Exception e) {
          log.error(e.getMessage(), e);
          throw new DAOException(e);
        }

        return (T) obj;
      }
    }.call();
  }

  /**
   * 获得数据库表名
   * 
   * @param clazz
   *          对象类
   * @return 表名
   */
  private static String getTableName(Class<? extends Object> clazz) {
    String table = null;

    TableName entity = clazz.getAnnotation(TableName.class);

    if (entity != null) {
      table = entity.name();
    } else {
      table = clazz.getSimpleName();
    }

    return "`" + table + "`";
  }

  /**
   * 插入一个对象,返回自增长后的值
   * 
   * @param dataSrc
   *          数据源
   * @param obj
   *          对象
   * @return 影响数据库的结果数
   */
  public long insert(DBRoute dbRoute, Object obj) throws DAOException {
    String table = getTableName(obj.getClass());

    StringBuilder sqlField = new StringBuilder();
    StringBuilder sqlValue = new StringBuilder();
    Class objClazz = obj.getClass();
    List<Object> params = new ArrayList<Object>();
    sqlField.append("INSERT INTO ").append(table).append("(");
    sqlValue.append(" VALUES (");

    for (Field field : getFields(objClazz)) {
      Object value = InvokerUtil.invokeGet(obj, field);

      if (value != null) {
        sqlField.append(getColumnName(field)).append(",");
        sqlValue.append("?,");
        params.add(value);
      }
    }

    sqlField.deleteCharAt(sqlField.length() - 1);
    sqlField.append(")");
    sqlValue.deleteCharAt(sqlValue.length() - 1);
    sqlValue.append(")");

    showSQL(dbRoute, sqlField.toString() + sqlValue.toString(), params.toArray());

    return insert(false, dbRoute, sqlField.toString() + sqlValue.toString(), params.toArray());
  }

  public long insert(boolean debug, DBRoute dbRoute, String query, Object... args) throws DAOException {
    Connection conn = null;
    PreparedStatement ps = null;
    ResultSet rset = null;

    try {
      conn = this.jdbcBaseDaoSupport.getConnection(dbRoute);
      ps = conn.prepareStatement(query, Statement.RETURN_GENERATED_KEYS);
      setArgs(ps, args);

      int res = ps.executeUpdate();

      if (res <= 0) {
        return 0L;
      }

      rset = ps.getGeneratedKeys();

      if (rset.next()) {
        return rset.getLong(1);
      } else {
        return (long) res;
      }
    } catch (SQLException e) {
      log.error(query + e.getMessage(), e);
      throw new DAOException(e);
    } finally {
      closeAll(rset, ps, conn, dbRoute);
    }
  }

  /**
   * 批量插入
   * 
   * @param dataSrc
   *          数据源
   * @param c
   *          对象集合
   * @return 影响数据库结果数
   */
  public long insertBatch(DBRoute dbRoute, Collection<? extends Object> c) throws DAOException {
    if (CollectionUtils.isEmpty(c)) {
      return 0;
    }

    Class objClazz = c.iterator().next().getClass();
    String table = getTableName(objClazz);
    StringBuilder sqlField = new StringBuilder();
    sqlField.append("INSERT INTO ").append(table).append("(");

    for (Field field : getFields(objClazz)) {

      sqlField.append(getColumnName(field)).append(",");

    }

    sqlField.deleteCharAt(sqlField.length() - 1);
    sqlField.append(")");

    StringBuilder sqlValue = new StringBuilder();
    sqlValue.append(" VALUES ");

    List<Object> params = new ArrayList<Object>();

    for (Object obj : c) {

      sqlValue.append("(");

      for (Field field : getFields(objClazz)) {
        Object value = InvokerUtil.invokeGet(obj, field);
        sqlValue.append("?,");
        params.add(value);
      }

      sqlValue.deleteCharAt(sqlValue.length() - 1);
      sqlValue.append("),");
    }

    sqlValue.deleteCharAt(sqlValue.length() - 1);

    showSQL(dbRoute, sqlField.toString() + sqlValue.toString(), params.toArray());

    return insert(false, dbRoute, sqlField.toString() + sqlValue.toString(), params.toArray());
  }

  /**
   * 插入或更新（会造成addTs不正确的问题）
   * 
   * @param dataSrc
   *          数据源
   * @param obj
   *          对象
   * @return 影响数据库的行数
   */
  public long insertOrUpdate(DBRoute dbRoute, Object obj) throws DAOException {

    String table = getTableName(obj.getClass());

    StringBuilder sqlField = new StringBuilder();
    StringBuilder sqlValue = new StringBuilder();
    Class objClazz = obj.getClass();
    List<Object> params = new ArrayList<Object>();
    sqlField.append("INSERT INTO ").append(table).append("(");
    sqlValue.append(" VALUES (");

    for (Field field : getFields(objClazz)) {
      Object value = InvokerUtil.invokeGet(obj, field);

      if (value != null) {
        sqlField.append(getColumnName(field)).append(",");
        sqlValue.append("?,");
        params.add(value);
      }
    }

    sqlField.deleteCharAt(sqlField.length() - 1);
    sqlField.append(")");
    sqlValue.deleteCharAt(sqlValue.length() - 1);
    sqlValue.append(")");

    StringBuilder sqlOnDuplicateKey = new StringBuilder();
    sqlOnDuplicateKey.append(" ON DUPLICATE KEY  UPDATE ");

    for (Field field : getFields(objClazz)) {

      sqlOnDuplicateKey.append(getColumnName(field)).append("= ?,");
      params.add(InvokerUtil.invokeGet(obj, field));
    }

    sqlOnDuplicateKey.deleteCharAt(sqlOnDuplicateKey.length() - 1);
    showSQL(dbRoute, sqlField.toString() + sqlValue.toString() + sqlOnDuplicateKey.toString(), params.toArray());

    return insert(false, dbRoute, sqlField.toString() + sqlValue.toString() + sqlOnDuplicateKey.toString(), params.toArray());
  }

  /**
   * 插入或更新（会造成addTs不正确的问题）
   * 
   * @param dataSrc
   *          数据源
   * @param obj
   *          对象
   * @return 影响数据库的行数
   */
  public long insertOrUpdateNotNull(DBRoute dbRoute, Object obj) throws DAOException {

    String table = getTableName(obj.getClass());

    StringBuilder sqlField = new StringBuilder();
    StringBuilder sqlValue = new StringBuilder();
    Class objClazz = obj.getClass();
    List<Object> params = new ArrayList<Object>();
    sqlField.append("INSERT INTO ").append(table).append("(");
    sqlValue.append(" VALUES (");

    for (Field field : getFields(objClazz)) {
      Object value = InvokerUtil.invokeGet(obj, field);

      if (value != null) {
        sqlField.append(getColumnName(field)).append(",");
        sqlValue.append("?,");
        params.add(value);
      }
    }

    sqlField.deleteCharAt(sqlField.length() - 1);
    sqlField.append(")");
    sqlValue.deleteCharAt(sqlValue.length() - 1);
    sqlValue.append(")");

    StringBuilder sqlOnDuplicateKey = new StringBuilder();
    sqlOnDuplicateKey.append(" ON DUPLICATE KEY  UPDATE ");

    for (Field field : getFields(objClazz)) {

      Object value = InvokerUtil.invokeGet(obj, field);
      if (value == null)
        continue;

      if (field.getAnnotation(PartitionID.class) != null) {
        continue;
      }

      sqlOnDuplicateKey.append(getColumnName(field)).append("= ?,");
      params.add(value);
    }

    sqlOnDuplicateKey.deleteCharAt(sqlOnDuplicateKey.length() - 1);
    showSQL(dbRoute, sqlField.toString() + sqlValue.toString() + sqlOnDuplicateKey.toString(), params.toArray());

    return insert(false, dbRoute, sqlField.toString() + sqlValue.toString() + sqlOnDuplicateKey.toString(), params.toArray());
  }

  /**
   * 工具字段插入或更新
   * 
   * @param dataSrc
   *          数据源
   * @param obj
   *          对象
   * @param fields
   *          字段逗号隔开
   * @param params
   *          参数
   * @return 影响数据库的结果数
   */
  public long insertOrUpdate(DBRoute dbRoute, Object obj, String fields, Object... params) throws DAOException {
    if (null == findByFields(dbRoute, obj.getClass(), fields, params)) {
      return insert(dbRoute, obj);
    } else {
      return update(dbRoute, obj);
    }
  }

  /**
   * 给对象的某个成员设置（set）
   * 
   * @param o
   *          对象
   * @param filedName
   *          字段名
   * @param value
   *          值
   */
  private static void setValue(Object o, Class objClazz, Field field, Object value) {
    if (value == null) {
      return;
    }

    Class fieldClazz = field.getType();

    Object fieldValue = null;

    if (String.class.equals(fieldClazz)) {
      fieldValue = value.toString();
    } else if (Integer.class.equals(fieldClazz) || int.class.equals(fieldClazz)) {
      fieldValue = new Integer(value.toString());
    } else if (Long.class.equals(fieldClazz) || long.class.equals(fieldClazz)) {
      fieldValue = new Long(value.toString());
    } else if (java.util.Date.class.equals(fieldClazz)) {
      fieldValue = new Date(((java.sql.Timestamp) value).getTime());
    } else if (Float.class.equals(fieldClazz) || float.class.equals(fieldClazz)) {
      fieldValue = new Float(value.toString());
    } else if (Double.class.equals(fieldClazz) || double.class.equals(fieldClazz)) {
      fieldValue = new Double(value.toString());
    } else if (BigDecimal.class.equals(fieldClazz)) {
      fieldValue = new BigDecimal(value.toString());
    } else if (Boolean.class.equals(fieldClazz) || boolean.class.equals(fieldClazz)) {
      if (value.toString().equals("1") || value.toString().equalsIgnoreCase("true")) {
        value = "true";
      }

      fieldValue = new Boolean(value.toString());
    } else {
      log.error("this filed of value will not be seted because of unprocessed type  " + fieldClazz + " and value = " + value + " and valueClass = "
          + value.getClass());

      return;
    }

    InvokerUtil.invokeSet(o, field, fieldValue);
  }

  /**
   * 忽略字段（被static或<code>@Transient</code>或Transient所修饰的字段）
   * 
   * @param field
   *          字段
   * @return true 忽略
   */
  private static boolean skipField(Field field) {
    int modifiers = field.getModifiers();

    return (field.getAnnotation(ColumIngore.class) != null) || Modifier.isStatic(modifiers) || Modifier.isTransient(modifiers);
  }

  public long update(DBRoute dbRoute, Object obj) throws DAOException {
    return this.update(dbRoute, obj, false);
  }

  public long updateNotNull(DBRoute dbRoute, Object obj) throws DAOException {
    return this.update(dbRoute, obj, true);
  }

  /**
   * 更新一个对象
   * 
   * @param dataSrc
   *          数据源
   * @param obj
   *          对象
   * @return 影响数据库的结果数
   */
  public long update(DBRoute dbRoute, Object obj, boolean notnull) throws DAOException {
    String table = getTableName(obj.getClass());

    Class objClazz = obj.getClass();
    StringBuilder sql = new StringBuilder();
    sql.append("UPDATE ").append(table).append(" SET ");

    List<Object> params = new ArrayList<Object>();

    for (Field field : getFields(objClazz)) {
      Object value = InvokerUtil.invokeGet(obj, field);
      if (value == null)
        continue;
      if (field.getAnnotation(PartitionID.class) != null) {
        continue;
      }
      sql.append(getColumnName(field)).append("= ?,");
      params.add(value);
    }

    sql.deleteCharAt(sql.length() - 1);
    sql.append(" WHERE ");

    boolean uniqueId = false;

    boolean partitionId = false;
    for (Field field : getFields(objClazz)) {
      if (field.getAnnotation(TableID.class) != null) {
        Object val = InvokerUtil.invokeGet(obj, field);
        uniqueId = uniqueId || (val != null);
        sql.append(getColumnName(field)).append(" = ? AND ");
        params.add(val);
      }
      if (field.getAnnotation(TableUnique.class) != null) {
        Object val = InvokerUtil.invokeGet(obj, field);
        uniqueId = uniqueId || (val != null);
        sql.append(getColumnName(field)).append(" = ? AND ");
        params.add(val);
      }

      if (field.getAnnotation(PartitionID.class) != null) {
        Object val = InvokerUtil.invokeGet(obj, field);
        partitionId = (val != null);
        sql.append(getColumnName(field)).append(" = ? AND ");
        params.add(val);
      } else {
        partitionId = true;
      }
    }
    if (!partitionId)
      throw new DAOException("can not update while partitionId is null");

    if (!uniqueId)
      throw new DAOException("can not update while uniqueid or id is null");

    sql.delete(sql.length() - 4, sql.length());

    showSQL(dbRoute, sql.toString(), params.toArray());

    return update(false, dbRoute, sql.toString(), params.toArray());
  }

  /**
   * 批量更新
   * 
   * @param dataSrc
   *          数据源
   * @param c
   *          对象集合
   * @return 影响数据库的结果数
   */
  public long updateBatch(DBRoute dbRoute, Collection<? extends Object> c) throws DAOException {
    long count = 0;

    for (Object object : c) {
      if (object == null) {
        continue;
      }

      count += update(dbRoute, object);
    }

    return count;
  }

  public JDBCBaseDaoSupport getJdbcBaseDaoSupport() {
    return jdbcBaseDaoSupport;
  }

  public void setJdbcBaseDaoSupport(JDBCBaseDaoSupport jdbcBaseDaoSupport) {
    this.jdbcBaseDaoSupport = jdbcBaseDaoSupport;
  }
}
